/*************************/
/* Initialise DirectDraw */
/*************************/

#ifndef _VC10EA_

#include <ddraw.h>
#include <stdio.h>
#include "../Win32/DirectX.h"

#define TRACE(a,b) printf(a,b)

int DirectXinted=0;

#else //ndef _VC10EA_

int DirectXinted;

#endif //ndef _VC10EA_

DDPIXELFORMAT ddPixelFormat;// Pixel format description for the overlay surface 
HRESULT		  ddrval;// Return value from DirectDraw API calls 
DDSURFACEDESC ddsd;// Surface description used in creation of primary and overlay surfaces 
LPDIRECTDRAW  lpDD;// Pointer to the global DirectDraw object 
LPDIRECTDRAWSURFACE lpPrimary;// Pointer to the primary surface 
LPDIRECTDRAWSURFACE  lpOverlay;// Pointer to the overlay surface 
LPDIRECTDRAWCLIPPER lpClipper;// Pointer to the clipper 
RECT		  rectClient;// Window size and position 
RECT		  rectOverlay;// Overlay source rectangle 
DDOVERLAYFX   ddofx;// Effects used in displaying the overlay 
DWORD		  dwFlags;// Work variable used in the move/size code 
DWORD		  dwKeyColour;// The colour to be used as the key for the overlay. 
//This value will change depending upon the primary surface mode. 
DDSCAPS		  caps;
int client_w;

BYTE* lock_surface (LPDIRECTDRAWSURFACE lpdds) 
{
    HRESULT	ddrval;

	ddrval = IDirectDrawSurface_Lock (lpdds, NULL, &ddsd, DDLOCK_WAIT|DDLOCK_WRITEONLY, NULL);
	if (ddrval==DDERR_SURFACELOST) {
		ddrval = IDirectDrawSurface_Restore (lpdds);
		if (ddrval != DD_OK) {
			TRACE ("restore failed %d\n",0);
			exit (-1);
		}
	} else if (ddrval != DD_OK) {
		TRACE("lock failed %hi\n", ddrval);
		exit (-1);
	}

	return (BYTE*)ddsd.lpSurface;
}

BOOL unlock_surface (LPDIRECTDRAWSURFACE lpdds,unsigned char* surface)
{
    HRESULT	ddrval;

	ddrval = IDirectDrawSurface_Unlock (lpdds, surface);
	if (ddrval != DD_OK) {
		TRACE("unlock failed %d\n",0);
		return FALSE;
	}

	return TRUE;
}


int InitDX(HWND hwnd,int W,int H)
{
	BYTE *surface;
	DWORD * mvr;
	int i,j;
	DDSURFACEDESC dd;


	ddrval = DirectDrawCreate(NULL, &lpDD, NULL);
	if(ddrval != DD_OK)
	{
	  TRACE("Can't initialise DirectDraw ! 0x%08lx\n", ddrval);
	  return(FALSE);
	}


	ddrval = IDirectDraw_SetCooperativeLevel(lpDD, hwnd, DDSCL_NORMAL);
	if(ddrval != DD_OK)
	{
	  TRACE("Can't set DirectDraw cooperative level ! 0x%08lx\n", ddrval);
	  IDirectDraw_Release(lpDD);
	  return(FALSE);
	}

		
	/******************************/
	/* Create the primary surface */
	/******************************/
	ZeroMemory(&ddsd, sizeof(ddsd));
	ddsd.dwSize = sizeof(DDSURFACEDESC);
	ddsd.dwFlags = DDSD_CAPS;
	ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
	ddrval = IDirectDraw_CreateSurface( lpDD, &ddsd, &lpPrimary, NULL );



	if( ddrval != DD_OK )
	{
	  TRACE("Can't create primary surface ! 0x%08lx\n", ddrval);
	  IDirectDraw_Release(lpDD);
	  return(FALSE);
	}


	/******************************/
	/* Create the overlay surface */
	/******************************/
	ZeroMemory(&ddPixelFormat,sizeof(ddPixelFormat));
	ddPixelFormat.dwFlags = DDPF_FOURCC;
	ddPixelFormat.dwSize = sizeof(DDPIXELFORMAT);
	ddPixelFormat.dwFourCC = mmioFOURCC('Y','U','Y','2');
//	ddPixelFormat.dwFourCC = mmioFOURCC('U','Y','V','Y');
	ddPixelFormat.dwYUVBitCount=16;

	ddsd.dwSize = sizeof(DDSURFACEDESC);
	ddsd.dwFlags = DDSD_CAPS |DDSD_HEIGHT |DDSD_WIDTH |DDSD_PIXELFORMAT|DDSD_PITCH;
	ddsd.ddsCaps.dwCaps = DDSCAPS_OVERLAY;
	ddsd.dwWidth  = W;
	ddsd.dwHeight = H; /* Change these values as appropriate (obviously !) */
	ddsd.lPitch	  = W*2;

	memcpy(&(ddsd.ddpfPixelFormat), &ddPixelFormat, sizeof(DDPIXELFORMAT));

	ddrval = IDirectDraw_CreateSurface( lpDD, &ddsd, &lpOverlay, NULL );

	if( ddrval != DD_OK )
	{
	  TRACE("Can't create overlay surface ! 0x%08lx\n", ddrval);
	  IDirectDrawSurface_Release(lpPrimary);
	  IDirectDraw_Release(lpDD);
	  return(FALSE);
	}

	/***********************************/
	/* Create a clipper for our window */
	/***********************************/
	ddrval = IDirectDraw_CreateClipper(lpDD, 0, &lpClipper, NULL);
	if( ddrval != DD_OK )
	{
	  TRACE("Can't create DirectDraw clipper ! 0x%08lx\n", ddrval);
	}
	else
	  ddrval = IDirectDrawClipper_SetHWnd(lpClipper, 0, hwnd);

	/*********************************/
	/* Position and show the overlay */
	/*********************************/
	SetRect(&rectOverlay, 0, 0,W,H);
#ifdef _VC10EA_
	::
#endif //def _VC10EA_
	GetWindowRect(hwnd, &rectClient);
	client_w = rectClient.right-rectClient.left;
	//SetRect(&rectClient, 0, 0,W,H);
	memset (&ddofx, 0, sizeof(ddofx));
	ddofx.dwSize = sizeof(DDOVERLAYFX);
	dwFlags = DDOVER_SHOW;//|DDOVER_INTERLEAVED|DDOVER_BOBHARDWARE;
						 // last 2 fo h/w de-interlacing
	ddrval = IDirectDrawSurface_UpdateOverlay(lpOverlay,
											  &rectOverlay,
											  lpPrimary,
											  &rectClient,
											  dwFlags,
											  &ddofx);
	if(ddrval != DD_OK)
	{
	  // Oops - can't update overlay. Put your error handling code here.
		printf("DirectX failure!!!!!!\n");
	  return 0;
	}

	surface=lock_surface(lpOverlay); 
	// Get surface pitch ( diffrent for different cards)
	ZeroMemory(&dd, sizeof(dd));
	dd.dwSize = sizeof(DDSURFACEDESC);
	IDirectDrawSurface_GetSurfaceDesc(lpOverlay,&dd);
	if (dd.lPitch < (W<<1)) dd.lPitch=(W<<1);

	//clean surface
	mvr=(DWORD*)surface;
	for(i=0;i<H;i++)
	{
		for(j=0;j<W/2;j++)
			*mvr++=0x80008000;
		mvr+=((dd.lPitch-W*2)>>2);
	}
	unlock_surface (lpOverlay,surface);

	DirectXinted=1;
	return 1;
}

int OnMoveResizeDX(HWND hwnd,int W,int H)
{
	if (!DirectXinted) return 0;
	/***************************************/
	/* Show the overlay with colour keying */
	/***************************************/

	/*************************/
	/* Where is the window ? */
	/*************************/
#ifdef _VC10EA_
	::
#endif //def _VC10EA_
	GetWindowRect(hwnd, &rectClient);

	/*********************************/
	/* Position and show the overlay */
	/*********************************/
	SetRect(&rectOverlay, 0, 0, W,H);
	ddofx.dwSize = sizeof(DDOVERLAYFX);
	ddofx.dckDestColorkey.dwColorSpaceLowValue = dwKeyColour;
	ddofx.dckDestColorkey.dwColorSpaceHighValue = dwKeyColour;

	dwFlags = //DDOVER_KEYDESTOVERRIDE | 
		DDOVER_SHOW;
	ddrval = IDirectDrawSurface_UpdateOverlay(lpOverlay,
											  &rectOverlay,
											  lpPrimary,
											  &rectClient,
											  dwFlags,
											  &ddofx);
	if(ddrval != DD_OK)
	{
	  // Oops - can't update overlay. Put your error handling code here.
		printf("DirectX failure!!!!!!\n");
		return 0;
	}
	return 1;
}


void DirectYUV(HWND hwnd,BYTE* Y,BYTE* U,BYTE* V,int W,int H,int addField)
{
	if (!DirectXinted) return;
	else{
		BYTE *surface=lock_surface(lpOverlay);
		DDSURFACEDESC dd;
		DWORD *out= (DWORD*) surface ;
		int y;
		// Get surface pitch ( diffrent for different cards)
		ZeroMemory(&dd, sizeof(dd));
		dd.dwSize = sizeof(DDSURFACEDESC);
		IDirectDrawSurface_GetSurfaceDesc(lpOverlay,&dd);
		if (dd.lPitch < (W<<1)) dd.lPitch=(W<<1);
		out+=addField*(dd.lPitch>>2); //skip upper field
		for (y=0;y<H;y++) {
			int sz=W;
	//------------------ MMX code ----------------------------
	#ifdef _MMX_
		__int64 zer=0x8080808080808080;
		__asm {
			MOV		ECX,sz
			SHR		ECX,4
			MOV		EAX,Y
			MOV		EBX,U
			MOV		EDX,V
			MOVQ    MM7,zer
			
			PREFETCHNTA [EAX]
			PREFETCHNTA [EBX]
			PREFETCHNTA [EDX]
			MOV		EDI,out
			//PXOR	MM7,MM7

	Exec16:	
			MOVQ	MM2,[EBX]
			PREFETCHT0 [EAX+32]
			MOVQ	MM3,[EDX]
			PREFETCHT0 [EBX+32]
			MOVQ	MM4,MM2
			MOVQ	MM0,[EAX]
			PREFETCHT0 [EDX+32]
			MOVNTQ  [EBX],MM7
			
			
			MOVQ	MM1,[EAX+8]		
			PUNPCKLBW MM2,MM3			// V3 U3 V2 U2 V1 U1 V0 U0
			MOVNTQ  [EDX],MM7
			PUNPCKHBW MM4,MM3			// V7 U7 V6 U6 V5 U5 V4 U4
			MOVNTQ  [EAX],MM7
			MOVQ	MM5,MM0
			PUNPCKLBW MM0,MM2			// V1 Y3 U1 Y2 V0 Y1 U0 Y0
			MOVQ	MM6,MM1
			MOVNTQ	[EDI],MM0
			PUNPCKHBW MM5,MM2			// V3 Y7 U3 Y6 V2 Y5 U2 Y4
			MOVNTQ	[EDI+8],MM5
			PUNPCKLBW MM1,MM4			// V5 YB U5 YA V4 Y9 U4 Y8
			MOVNTQ	[EDI+16],MM1
			PUNPCKHBW MM6,MM4			// V7 YF U7 YE V6 YD U6 YC
			//PREFETCHT0 [EAX+16]
			MOVNTQ	[EDI+24],MM6
			ADD		EDX,8
			MOVNTQ  [EAX+8],MM7
			ADD		EBX,8
			ADD		EDI,32
			ADD		EAX,16
			LOOP 	Exec16
		}
		out+=dd.lPitch>>2;
		Y+=W;
		U+=W>>1;
		V+=W>>1;
	#else
	//------------------ C-code ----------------------------
		sz=sz>>1;
		while(sz--) {
				*out++=
					(Y[0])+(((U[0]))<<8)+
					(Y[1]<<16)+(((V[0]))<<24);
				Y[0]=Y[1]=U[0]=V[0]=0x80;//cleanup
				Y+=2;U+=1;V+=1;

		}
		out+=(dd.lPitch-W*2)>>2;
	#endif
		}
	#ifdef _MMX_
		_asm EMMS;

	#endif 
		unlock_surface (lpOverlay,surface);
	}
}

